# Copyright (c) 2023 Presto Labs Pte. Ltd.
# Author: leon

from typing import List, Dict, Tuple, Any

from absl import app
from web3 import Web3

from coin.exchange.uniswap_v2.kr_rest.native_private_client_v2 import UniswapV2NativePrivateClientV2
from coin.exchange.uniswap_v3.kr_rest.native_private_client_v2 import UniswapV3NativePrivateClientV2


def query_account_balance_impl(
    blockchain_name: str,
    mea: str,
    wallet_address: str,
    currencies: List[str],
    web3: Web3 = None,
) -> Dict[str, Dict[str, float]]:
    if 'ETH' not in currencies:
        currencies.append('ETH')
    if 'WETH' not in currencies:
        currencies.append('WETH')
    if mea == 'Spot.Uniswap.v2':
        npc = UniswapV2NativePrivateClientV2(web3=web3)
        return npc.get_balances(wallet_address, currencies)
    elif mea == 'Spot.Uniswap.v3':
        npc = UniswapV3NativePrivateClientV2(blockchain_name=blockchain_name, web3=web3)
        return npc.get_balances(
            wallet_address=wallet_address,
            currencies=currencies,
        )
    elif mea == 'Spot.Uniswap.v3-arbitrum':
        npc = UniswapV3NativePrivateClientV2(blockchain_name=blockchain_name, web3=web3)
        return npc.get_balances(
            wallet_address=wallet_address,
            currencies=currencies,
        )
    else:
        raise NotImplementedError(blockchain_name, mea)


def query_nft_token_info_impl(
    blockchain_name: str,
    mea: str,
    wallet_address: str,
    symbol: str,
    web3: Web3 = None,
) -> Dict[str, Dict[str, Any]]:
    if mea == 'Spot.Uniswap.v2':
        raise NotImplementedError()
    elif mea == 'Spot.Uniswap.v3':
        npc = UniswapV3NativePrivateClientV2(blockchain_name=blockchain_name, web3=web3)
        return npc.get_nft_token_info(
            wallet_address=wallet_address,
            symbol=symbol,
        )
    elif mea == 'Spot.Uniswap.v3-arbitrum':
        npc = UniswapV3NativePrivateClientV2(blockchain_name=blockchain_name, web3=web3)
        return npc.get_nft_token_info(
            wallet_address=wallet_address,
            symbol=symbol,
        )
    else:
        raise NotImplementedError(blockchain_name, mea)


def query_submit_order_impl(
    blockchain_name: str,
    mea: str,
    wallet_address: str,
    symbol: str,
    price: float,
    qty: float,
    side: str,
    web3: Web3 = None,
) -> Tuple[bool, str or None, float or None]:
    if mea == 'Spot.Uniswap.v2':
        npc = UniswapV2NativePrivateClientV2(web3=web3)
        return npc.submit_order(wallet_address, symbol, price, qty, side)
    elif mea == 'Spot.Uniswap.v3':
        npc = UniswapV3NativePrivateClientV2(blockchain_name=blockchain_name, web3=web3)
        return npc.submit_order(
            wallet_address=wallet_address,
            symbol=symbol,
            price=price,
            qty=qty,
            side=side,
        )
    elif mea == 'Spot.Uniswap.v3-arbitrum':
        npc = UniswapV3NativePrivateClientV2(blockchain_name=blockchain_name, web3=web3)
        return npc.submit_order(
            wallet_address=wallet_address,
            symbol=symbol,
            price=price,
            qty=qty,
            side=side,
        )
    else:
        raise NotImplementedError(blockchain_name, mea)


def query_provide_liquidity_impl(
    blockchain_name: str,
    mea: str,
    wallet_address: str,
    symbol: str,
    min_price: float,
    max_price: float,
    web3: Web3 = None,
) -> Tuple[bool, str or None, float or None]:
    if mea == 'Spot.Uniswap.v2':
        raise NotImplementedError(blockchain_name, mea)
    elif mea == 'Spot.Uniswap.v3':
        npc = UniswapV3NativePrivateClientV2(blockchain_name=blockchain_name, web3=web3)
        return npc.provide_liquidity(
            wallet_address=wallet_address,
            symbol=symbol,
            min_price=min_price,
            max_price=max_price,
        )
    elif mea == 'Spot.Uniswap.v3-arbitrum':
        npc = UniswapV3NativePrivateClientV2(blockchain_name=blockchain_name, web3=web3)
        return npc.provide_liquidity(
            wallet_address=wallet_address,
            symbol=symbol,
            min_price=min_price,
            max_price=max_price,
        )
    else:
        raise NotImplementedError(blockchain_name, mea)


def query_withdraw_liquidity_impl(
    blockchain_name: str,
    mea: str,
    wallet_address: str,
    symbol: str,
    web3: Web3 = None,
) -> Tuple[bool, str or None]:
    if mea == 'Spot.Uniswap.v2':
        raise NotImplementedError(blockchain_name, mea)
    elif mea == 'Spot.Uniswap.v3':
        npc = UniswapV3NativePrivateClientV2(blockchain_name=blockchain_name, web3=web3)
        return npc.withdraw_liquidity(
            wallet_address=wallet_address,
            symbol=symbol,
        )
    elif mea == 'Spot.Uniswap.v3-arbitrum':
        npc = UniswapV3NativePrivateClientV2(blockchain_name=blockchain_name, web3=web3)
        return npc.withdraw_liquidity(
            wallet_address=wallet_address,
            symbol=symbol,
        )
    else:
        raise NotImplementedError(blockchain_name, mea)


def main(_):
    test_wallet_address = '0x7bAB600B920aC10C3C6706BE17DDc1B80dBE12c1'
    # Spot.Uniswap.v2 case
    # print(query_account_balance_impl(
    #     'ethereum', 'Spot.Uniswap.v2', test_wallet_address,
    #     ['ETH', 'WETH', 'USDT', 'USDC', 'CCX']))
    # print(query_submit_order_impl(
    #     'ethereum', 'Spot.Uniswap.v2', test_wallet_address,
    #     'ETH-USDC', 1760, 0.1, 'BUY'))
    # print(query_submit_order_impl(
    #     'ethereum', 'Spot.Uniswap.v2', test_wallet_address,
    #     'ETH-USDC', 1730, 0.1, 'SELL'))
    # Spot.Uniswap.v3 case
    # print(query_account_balance_impl(
    #     'ethereum', 'Spot.Uniswap.v3', test_wallet_address,
    #     ['ETH', 'WETH', 'USDT', 'USDC', 'CCX']))
    # print(query_submit_order_impl(
    #     'ethereum', 'Spot.Uniswap.v3', test_wallet_address,
    #     'ETH-USDC.5bp', 1760, 0.1, 'BUY'))
    # print(query_submit_order_impl(
    #     'ethereum', 'Spot.Uniswap.v3', test_wallet_address,
    #     'ETH-USDC.5bp', 1730, 0.1, 'SELL'))
    # print(query_provide_liquidity_impl(
    #     'ethereum', 'Spot.Uniswap.v3', test_wallet_address, 'ETH-USDC.5bp', 1700, 1900))
    # print(query_nft_token_info_impl(
    #     'ethereum', 'Spot.Uniswap.v3', test_wallet_address, 'ETH-USDC.5bp'))
    # print(query_withdraw_liquidity_impl(
    #     'ethereum', 'Spot.Uniswap.v3', test_wallet_address, 'ETH-USDC.5bp'))
    # Spot.Uniswap.v3-arbitrum case
    # print(query_account_balance_impl(
    #     'arbitrum', 'Spot.Uniswap.v3-arbitrum', test_wallet_address,
    #     ['ETH', 'WETH', 'USDT', 'USDC']))
    # print(query_submit_order_impl(
    #     'arbitrum', 'Spot.Uniswap.v3-arbitrum', test_wallet_address,
    #     'ETH-USDC.5bp', 1930, 0.1, 'BUY'))
    # print(query_submit_order_impl(
    #     'arbitrum', 'Spot.Uniswap.v3-arbitrum', test_wallet_address,
    #     'ETH-USDC.5bp', 1900, 0.1, 'SELL'))
    # print(query_provide_liquidity_impl(
    #     'arbitrum', 'Spot.Uniswap.v3-arbitrum', test_wallet_address, 'ETH-USDC.5bp', 1800, 2000))
    # print(query_nft_token_info_impl(
    #     'arbitrum', 'Spot.Uniswap.v3-arbitrum', test_wallet_address, 'ETH-USDC.5bp'))
    # print(query_withdraw_liquidity_impl(
    #     'arbitrum', 'Spot.Uniswap.v3-arbitrum', test_wallet_address, 'ETH-USDC.5bp'))
    # from web3 import Web3, HTTPProvider
    # from coin.exchange.uniswap_base.constants import (
    #     PRODUCTION_RPC_URL,
    # )
    # from coin.exchange.util.web3.signing_util import calculate_fill_price
    # web3 = Web3(HTTPProvider(PRODUCTION_RPC_URL["arbitrum"]))
    # rcpt = web3.eth.get_transaction_receipt("0xb83ceea6bf3bc9cb14cc458685de38f205f17c3d53412fb784ca3bdacef5497a")
    # print(calculate_fill_price(rcpt, 'ETH-USDC.5bp', 'arbitrum'))


if __name__ == '__main__':
    app.run(main)
